package com.wxzhou.wangzhuan.service;

import com.wxzhou.wangzhuan.entity.*;
import com.wxzhou.wangzhuan.repository.ButieRespository;
import com.wxzhou.wangzhuan.util.RedisKeyUtil;
import io.quarkus.cache.CacheKey;
import io.smallrye.mutiny.Uni;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ThreadLocalRandom;
import java.util.stream.Collectors;

/**
 * 补贴服务
 */
@ApplicationScoped
public class ButieService {

    @Inject
    ButieRespository butieRespository;

    @Inject
    RedisService redisService;

    @Inject
    RedisKeyUtil redisKeyUtil;

    /**
     * 根据用户和业务场景，查询其补贴计划
     * 查询结果可能是多个，因为可能是批量化的请求，有可能1次请求含多个广告位，因此可能有多个补贴
     * 线上需添加缓存！
     *
     * @param userid
     * @param senses
     * @return
     */
//    @CacheResult(cacheName = CacheNames.KEY_USER_BUTIE_PREFIX)
    public Uni<List<WzButie>> findAllButieBy(@CacheKey Long userid, Set<Integer> senses) {
        String redisKey = redisKeyUtil.buildButieKey(userid);
        if (senses != null && senses.size() > 0) {
            return redisService.getList(redisKey, WzButie.class)
                    .onItem().transformToUni(buties -> {
                        if (buties != null && buties.size() > 0) {
                            return Uni.createFrom().item(buties);
                        } else {
                            return butieRespository.findAllButieBy(userid, senses.stream().toList())
                                    .onItem().transform(wzButies -> {
                                        if (wzButies != null && wzButies.size() > 0) {
                                            redisService.addList(redisKey, wzButies).subscribe().with(unused -> {
                                            }, throwable -> {
                                            });
                                        }
                                        return wzButies;
                                    });
                        }
                    });
        }
        return Uni.createFrom().item(new ArrayList<>());
    }

    /**
     * 根据广告数据、补贴配置获取补贴结果
     *
     * @param adMaxAmount       单条广告最大收益 非补贴受用
     * @param adUserPercent     用户收益比例，非补贴受用
     * @param goodInfos
     * @param wzButies
     * @param userTodayButieMap 用户今日补贴键值对，key：sense，value，已补贴金额
     * @return
     */
    public Uni<List<AdLogAndButie>> calc(BigDecimal adMaxAmount, BigDecimal adUserPercent, List<AdLog> goodInfos, List<WzButie> wzButies, Map<String, BigDecimal> userTodayButieMap) {
        //每一条广告都去命中补贴(根据sense)，并得到一个最终的补贴金额。补贴金额+ECPM是最终收益。如果拿不到，正常返回AdLog
        List<AdLogAndButie> newGoodList = new ArrayList<>();

        for (AdLog adLog : goodInfos) {
            Integer adSense = adLog.getAd_sense();
            BigDecimal todayUserButieAmountOfSense = BigDecimal.ZERO;
            if (userTodayButieMap.containsKey(String.valueOf(adSense))) {
                todayUserButieAmountOfSense = userTodayButieMap.get(String.valueOf(adSense));
            }
            WzButie thisButie = wzButies != null && wzButies.size() > 0 ? wzButies.stream().filter(wzButie -> wzButie.getSense() == adSense).findFirst().orElse(null) : null;
            AdLogAndButie adLogAndButie = new AdLogAndButie(adLog);
            if (thisButie != null && !thisButie.getHasNotStart() && !thisButie.getHasExpired()) {

                ButieType butieType = ButieType.fromCode(thisButie.getButie_type()); //补贴方式，1
                BigDecimal dayMaxAmount = thisButie.getDay_max_amount();//当日补贴最大金额
                //已补贴最大金额
                BigDecimal dayAmountLeft = thisButie.getDay_amount_left(); //随机左值
                BigDecimal dayAmountRight = thisButie.getDay_amount_right();//随机右值

                BigDecimal butieAmount = generateRandomMoney(dayAmountLeft, dayAmountRight); //随机dayAmountLeft到dayAmountRight之间
                //本次补贴金额+今日累计补贴金额超过今日补贴上限
                if (butieAmount.add(todayUserButieAmountOfSense).compareTo(dayMaxAmount) <= 0) {
                    //暂时注释掉同步的问题。
//                if (butieAmount.add(todayUserButieAmountOfSense).compareTo(dayMaxAmount) <= 0 && adLog.getBs_ac() == AdBusinessAction.SUCCESS_SHOW.getCode()) {
                    //没有超过上限，累加今日补贴金额
                    userTodayButieMap.putIfAbsent(String.valueOf(adSense), todayUserButieAmountOfSense.add(butieAmount));
                    if (butieType == ButieType.BUTIE_DEFAULT) {
                        adLog.setUser_amount(butieAmount); //直接就是补贴，忽略各种其他条件
                    } else {
                        //随机金额+ECPM，转换为分
                        adLog.setUser_amount(butieAmount.add(new BigDecimal(adLog.getEcpm()).divide(new BigDecimal("1000"), 6, RoundingMode.DOWN)));
                    }
                    //设置补贴金额
                    adLog.setButie_amount(butieAmount);
                    adLog.setRemark(adLog.getRemark());
                    adLogAndButie.setWzButie(thisButie);
                } else {
                    //不含补贴
                    //先统一换算成分，再换算成元和金币等单位
                    BigDecimal amountFen = new BigDecimal(adLog.getEcpm()).multiply(adUserPercent).divide(new BigDecimal("1000"), 6, RoundingMode.DOWN); //分.
                    //根据日志中的数据,判断用户上报的数据是否满足系统配置的完整收益(广告展示成功,并且拿到ecpm,并且根据ecpm),从上报中找出有ecpm的并且bs_ac=1(展示拿价)的
                    BigDecimal finalUserAmountFen = amountFen.compareTo(adMaxAmount) <= 0 ? amountFen : adMaxAmount; //收益控制
                    adLog.setUser_amount(finalUserAmountFen);
                }
            } else {
                //不含补贴
                BigDecimal amountFen = new BigDecimal(adLog.getEcpm()).multiply(adUserPercent).divide(new BigDecimal("1000"), 6, RoundingMode.DOWN); //分.
                //根据日志中的数据,判断用户上报的数据是否满足系统配置的完整收益(广告展示成功,并且拿到ecpm,并且根据ecpm),从上报中找出有ecpm的并且bs_ac=1(展示拿价)的
                BigDecimal finalUserAmountFen = amountFen.compareTo(adMaxAmount) <= 0 ? amountFen : adMaxAmount; //收益控制
                adLog.setUser_amount(finalUserAmountFen);
            }
            adLogAndButie.setAdLog(adLog);
            newGoodList.add(adLogAndButie);
        }
        return Uni.createFrom().item(newGoodList);
    }

    /**
     * 根据本次上报获取补贴记录
     *
     * @param adLogAndButies
     * @param transId
     * @return
     */
    public List<WzButieRecord> calcButieRecord(List<AdLogAndButie> adLogAndButies, String transId) {
        List<WzButieRecord> butieRecords = adLogAndButies.stream().map(logAndButie -> {
            WzButieRecord wzButieRecord = new WzButieRecord();
            WzButie wzButie = logAndButie.getWzButie();
            AdLog adLog = logAndButie.getAdLog();
            if (wzButie != null && adLog != null) {
                wzButieRecord.setButieId(wzButie.getId());
                wzButieRecord.setUserId(wzButie.getUserId());
                wzButieRecord.setTransId(transId);
                wzButieRecord.setSense(wzButie.getSense());
                wzButieRecord.setButie_type(wzButie.getButie_type());
                wzButieRecord.setDay_max_amount(wzButie.getDay_max_amount());
                wzButieRecord.setDay_amount_left(wzButie.getDay_amount_left());
                wzButieRecord.setDay_amount_right(wzButie.getDay_amount_right());
                wzButieRecord.setStart_at(wzButie.getStart_at());
                wzButieRecord.setEnd_at(wzButie.getEnd_at());
                wzButieRecord.setCreatedAt(LocalDateTime.now());
                wzButieRecord.setRemark("");
                wzButieRecord.setAmount(adLog.getButie_amount());
                return wzButieRecord;
            }
            return null;
        }).filter(record -> record != null).collect(Collectors.toList());
        return butieRecords;
    }


    /**
     * 生成指定范围内的随机金额（精确到分）
     *
     * @param min 最小金额
     * @param max 最大金额
     * @return 随机金额
     */
    public static BigDecimal generateRandomMoney(BigDecimal min, BigDecimal max) {
        if (min.compareTo(max) > 0) {
            return BigDecimal.ZERO;
        }

        // 如果min和max相同，直接返回
        if (min.compareTo(max) == 0) {
            return min;
        }

        // 将金额转换为分（整数）进行计算
        Double minCents = min.doubleValue();
        Double maxCents = max.doubleValue();

        // 生成minCents到maxCents之间的随机整数（包含边界）
        Double randomCents = ThreadLocalRandom.current().nextDouble(minCents, maxCents);

        // 将分转换回金额，保留2位小数
        return BigDecimal.valueOf(randomCents).setScale(4, RoundingMode.DOWN);
    }

    public static void main(String[] args) {
        // 测试示例：100分到500分之间
        BigDecimal min = new BigDecimal("0.01");
        BigDecimal max = new BigDecimal("0.03");

        System.out.println("生成的随机金额示例（分单位）：");
        for (int i = 0; i < 10; i++) {
            BigDecimal randomMoney = generateRandomMoney(min, max);
            System.out.println("随机金额 " + (i + 1) + ": " + randomMoney + "分");
        }

        // 测试边界情况
        System.out.println("\n边界情况测试：");
        BigDecimal sameValue = generateRandomMoney(min, min);
        System.out.println("min=max时的结果: " + sameValue + "分");
    }
}
